
// === uuMeta.node ===
// depend: uuMeta
/*
uuMeta.node("<div>", ctx = body, pos = last) - return first node
uuMeta.node.text("text", ctx = body, pos = last) - return first text node
uuMeta.node.replace(newNode, oldNode) - return oldNode
uuMeta.node.remove(node) - return node
uuMeta.node.clear(parentNode) - return node
uuMeta.node.substance("<div>", ctx = owner) - return DocumentFragment
uuMeta.node.cutdown(ctx = body) - return DocumentFragment
uuMeta.node.normalize(ctx = body, depth = 0)
 */
(function uuMetaNodeScope() {
var _mm = uuMeta,
    _doc = document;

// uuMeta.node - insert Node
function insertNode(node,    // @param DocumentFragment/HTMLString:
                    context, // @param Node(= document.body): parent node
                    pos) {   // @param Number(= LAST_CHILD): insert position
                             // @return Node: first node
  var rv = node, ctx = context || _doc.body, pn = ctx.parentNode;

  if (typeof node === "string") { // "<div>" to div node
    node = substance(node, ctx);
    rv = node.firstChild;
  }
  switch (pos || 6) {
  case 1: ctx = pn; // break;
  case 5: ctx.firstChild ? ctx.insertBefore(node, ctx.firstChild)
                         : ctx.appendChild(node); break;
  case 4: ctx = pn; // break;
  case 6: ctx.appendChild(node); break;
  case 2: pn.insertBefore(node, ctx); break;
  case 3: (pn.lastChild === ctx) ? pn.appendChild(node)
                                 : pn.insertBefore(node, ctx.nextSibling);
  }
  return rv;
}

// uuMeta.node.text - insert TEXT_NODE or "TextString"
function insertTextNode(node,    // @param DocumentFragment/TextString:
                        context, // @param Node(= document.body): parent node
                        pos) {   // @param Number(= LAST_CHILD): insert position
                                 // @return Node: first text node
  return insertNode(typeof node === "string" ? _doc.createTextNode(node)
                                             : node, context, pos);
}

// uuMeta.node.replace - replace oldNode
function replaceNode(node,      // @param Node: new node
                     oldNode) { // @param Node: old node(cutout)
                                // @return Node: oldNode
  return oldNode.parentNode.replaceChild(node, oldNode);
}

// uuMeta.node.remove - remove node 
function removeNode(node) { // @param Node:
                            // @return Node:
  return node.parentNode.removeChild(node);
}

// uuMeta.node.clear - clear all children
function clearNode(node) { // @param Node: parent node
  node.innerHTML = "";
  return node; // return node
}

// uuMeta.node.substance - convert HTMLString into DocumentFragment
function substanceNode(html,      // @param HTMLString:
                       context) { // @param Node: node or owner document
                                  // @return DocumentFragment:
  var rv, range, placeholder;

  // use DOM Level2 Range Module
  if (_doc.createRange && !(_ua.opera && _ua.uaver >= 9.5)) {
    // http://d.hatena.ne.jp/uupaa/20081021
    range = _doc.createRange();
    range.selectNode(context);
    return range.createContextualFragment(html);
  }
  rv = _doc.createDocumentFragment();
  placeholder = _doc.createElement("div");
  placeholder.innerHTML = html;
  while (placeholder.firstChild) {
    rv.appendChild(placeholder.removeChild(placeholder.firstChild));
  }
  return rv;
}

// uuMeta.node.cutdown - cut all nodes less than context
function cutdownNode(context) { // @Node(= document.body): parent node
                                // @return DocumentFragment:
  var rv, ctx = context || _doc.body;

  if (_doc.createRange) {
    (rv = _doc.createRange()).selectNodeContents(ctx);
    return rv.extractContents(); // return DocumentFragment
  }
  rv = _doc.createDocumentFragment();
  while (ctx.firstChild) {
    rv.appendChild(ctx.removeChild(ctx.firstChild));
  }
  return rv;
}

// uuMeta.node.normalize - removes CRLF/blank-text/white-space/comment node
function normalize(context, // @param Node(= document.body): parent node
                   depth) { // @param Number(= 0): max depth
  function fn(elm, depth) {
    for (var w = elm.firstChild; w; w = w.nextSibling) {
      switch (w.nodeType) {
      case 1: (depth + 1 <= limit) && fn(w, depth + 1); break; // recursive
      case 3: if (blank.test(w.nodeValue)) { break; } // blank-text node?
      case 8: rv.push(w); // comment node
      }
    }
  }
  var rv = [], v, i = 0, blank = /\S/, limit = depth || 0;

  fn(context, 0);
  while ( (v = rv[i++]) ) {
    v.parentNode.removeChild(v);
  }
}

// --- initialize ---

// --- export ---
_mm.node = insertNode;
insertNode.text = insertTextNode;
insertNode.replace = replaceNode;
insertNode.remove = removeNode;
insertNode.clear = clearNode;
insertNode.substance = substanceNode;
insertNode.cutdown = cutdownNode;
insertNode.normalize = normalize;
insertNode.FIRST = 1; // uuMeta.node.FIRST - first sibling
insertNode.PREV  = 2; // uuMeta.node.PREV - prev sibling
insertNode.NEXT  = 3; // uuMeta.node.NEXT - next sibling
insertNode.LAST  = 4; // uuMeta.node.LAST - last sibling
insertNode.FIRST_CHILD = 5; // uuMeta.node.FIRST_CHILD - first child
insertNode.LAST_CHILD  = 6; // uuMeta.node.LAST_CHILD - last child

})(); // uuMeta.node scope

